﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
 
using Tao;
using Tao.OpenGl;
using Tao.Platform;
//using Tao.DevIl;

using VCMDL.NET;


namespace VoltGameEditor
{
    public class Framework
    {
		public static void MakeDefaultRoom(int CurrentTabIndex)
		{
			CreateRectangularPrism(new Vector3(0, 0, -8), 256, 256, 16);
			CreateRectangularPrism(new Vector3(0, 0, 136), 256, 256, 16);
			CreateRectangularPrism(new Vector3(-136, 0, 64), 16, 256, 128);
			CreateRectangularPrism(new Vector3(136, 0, 64), 16, 256, 128);
			CreateRectangularPrism(new Vector3(0, -136, 64), 256, 16, 128);
			CreateRectangularPrism(new Vector3(0, 136, 64), 256, 16, 128);
		}

        public static void CreateMap(string Name)
        {
			int i = Globals.NumDocs;

			//TextureStructs.AddDefaultTexture();

            mapDef.InitMapData(i, Name);
            
            Framework.CreateTree();

            mapDef.MapData[i].Map.Show(Program.mainWin.dp_docs);

			MakeDefaultRoom(i);

			Globals.NumDocs++;
        }

        static void CreateTree()
        {
            
            Framework.AddEntity(new Vector3(0, 0, 0), "worldspawn",true, null);
        }

        //3d shapes
		public static void CreateRectangularPrism(Vector3 origin, int length, int width, int height)
		{
			int i = mapDef.GetDocumentIndex();
			MapBrush Brush = new MapBrush();
			Brush.Name = "Brush" + (mapDef.MapData[i].Brushes.Count - 1).ToString();
			Brush.Origin = origin;
			Brush.KVPs.Add("name", Brush.Name);
			for (int j = 0; j < 6; j++)
			{
				Face face = new Face();
				//face.SetTexture(mapDef.MapData[i].GLvports.vports, "Games\\Quake 2\\Default.png");

				Brush.Faces.Add(face);
			}
			//Top
			Brush.Faces[0].Points.Add(new Vector3(origin.x - (length / 2), origin.y + (width / 2), origin.z + (height / 2)));
			Brush.Faces[0].Points.Add(new Vector3(origin.x - (length / 2), origin.y + (width / 2), origin.z - (height / 2)));
			Brush.Faces[0].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z - (height / 2)));
			Brush.Faces[0].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z + (height / 2)));

			Brush.Faces[0].TexCoords.Add(new Point(0, 0));
			Brush.Faces[0].TexCoords.Add(new Point(1, 0));
			Brush.Faces[0].TexCoords.Add(new Point(1, 1));
			Brush.Faces[0].TexCoords.Add(new Point(0, 1));
			//Bottom
			Brush.Faces[1].Points.Add(new Vector3(origin.x - (length / 2), origin.y - (width / 2), origin.z + (height / 2)));
			Brush.Faces[1].Points.Add(new Vector3(origin.x - (length / 2), origin.y - (width / 2), origin.z - (height / 2)));
			Brush.Faces[1].Points.Add(new Vector3(origin.x + (length / 2), origin.y - (width / 2), origin.z - (height / 2)));
			Brush.Faces[1].Points.Add(new Vector3(origin.x + (length / 2), origin.y - (width / 2), origin.z + (height / 2)));

			Brush.Faces[1].TexCoords.Add(new Point(0, 0));
			Brush.Faces[1].TexCoords.Add(new Point(1, 0));
			Brush.Faces[1].TexCoords.Add(new Point(1, 1));
			Brush.Faces[1].TexCoords.Add(new Point(0, 1));
			//Left
			Brush.Faces[2].Points.Add(new Vector3(origin.x - (length / 2), origin.y + (width / 2), origin.z + (height / 2)));
			Brush.Faces[2].Points.Add(new Vector3(origin.x - (length / 2), origin.y - (width / 2), origin.z + (height / 2)));
			Brush.Faces[2].Points.Add(new Vector3(origin.x - (length / 2), origin.y - (width / 2), origin.z - (height / 2)));
			Brush.Faces[2].Points.Add(new Vector3(origin.x - (length / 2), origin.y + (width / 2), origin.z - (height / 2)));

			Brush.Faces[2].TexCoords.Add(new Point(0, 0));
			Brush.Faces[2].TexCoords.Add(new Point(1, 0));
			Brush.Faces[2].TexCoords.Add(new Point(1, 1));
			Brush.Faces[2].TexCoords.Add(new Point(0, 1));
			//Right
			Brush.Faces[3].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z - (height / 2)));
			Brush.Faces[3].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z - (height / 2)));
			Brush.Faces[3].Points.Add(new Vector3(origin.x + (length / 2), origin.y - (width / 2), origin.z + (height / 2)));
			Brush.Faces[3].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z + (height / 2)));

			Brush.Faces[3].TexCoords.Add(new Point(0, 0));
			Brush.Faces[3].TexCoords.Add(new Point(1, 0));
			Brush.Faces[3].TexCoords.Add(new Point(1, 1));
			Brush.Faces[3].TexCoords.Add(new Point(0, 1));
			//Front
			Brush.Faces[4].Points.Add(new Vector3(origin.x - (length / 2), origin.y + (width / 2), origin.z - (height / 2)));
			Brush.Faces[4].Points.Add(new Vector3(origin.x - (length / 2), origin.y - (width / 2), origin.z - (height / 2)));
			Brush.Faces[4].Points.Add(new Vector3(origin.x + (length / 2), origin.y - (width / 2), origin.z - (height / 2)));
			Brush.Faces[4].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z - (height / 2)));

			Brush.Faces[4].TexCoords.Add(new Point(0, 0));
			Brush.Faces[4].TexCoords.Add(new Point(1, 0));
			Brush.Faces[4].TexCoords.Add(new Point(1, 1));
			Brush.Faces[4].TexCoords.Add(new Point(0, 1));
			//Back
			Brush.Faces[5].Points.Add(new Vector3(origin.x + (length / 2), origin.y + (width / 2), origin.z + (height / 2)));
			Brush.Faces[5].Points.Add(new Vector3(origin.x + (length / 2), origin.y - (width / 2), origin.z + (height / 2)));
			Brush.Faces[5].Points.Add(new Vector3(origin.x - (length / 2), origin.y - (width / 2), origin.z + (height / 2)));
			Brush.Faces[5].Points.Add(new Vector3(origin.x - (length / 2), origin.y + (width / 2), origin.z + (height / 2)));

			Brush.Faces[5].TexCoords.Add(new Point(0, 0));
			Brush.Faces[5].TexCoords.Add(new Point(1, 0));
			Brush.Faces[5].TexCoords.Add(new Point(1, 1));
			Brush.Faces[5].TexCoords.Add(new Point(0, 1));

			mapDef.MapData[i].Brushes.Add(Brush);

			TreeNodeEx node = new TreeNodeEx();
			IDictionary d = new Dictionary<string, string>();
			node.Text = "New Polyhedren";
			node.ObjIndex = mapDef.MapData[i].Brushes.Count;
			node.ItemType = MapObject.Type.Brush;
			node.ImageIndex = 1;
			node.SelectedImageIndex = 1;

			d["Name"] = node.Text;
			node.DefaultKVPs = d;

			mapDef.MapData[i].Tree.Nodes[0].Nodes.Add(node);
		}
        public static void CreateCylinder(Vector3 origin)
        {

        }
        public static void CreatePryamid(Vector3 origin)
        {

        }
        public static void CreateSphere(Vector3 origin)
        {

        }
        public static void CreateMesh(Vector3 origin)
        {

        }
        //----------

        public static void AddEntity(Vector3 origin, string name, bool FromNew, IDictionary ExtKVPs)
        {
            Entity Ent = new Entity();
			int i = mapDef.GetDocumentIndex();

            Ent.Name = name;
            Ent.Origin = origin;
            Ent.extModelRef = "";
            Ent.KVPs = ExtKVPs;

            mapDef.MapData[i].Entities.Add(Ent);
        }

        public static void AddGroup()
        {
            int i = mapDef.GetDocumentIndex();
 
            TreeNodeEx selnode = (TreeNodeEx)mapDef.MapData[i].Tree.SelectedNode;
            TreeNodeEx node = new TreeNodeEx("Group", 0, 0);


            if (mapDef.MapData[i].Tree.SelectedNode != null)
            {
                if (mapDef.MapData[i].Tree.SelectedNode.ImageIndex != 0 && mapDef.MapData[i].Tree.SelectedNode.ImageIndex != 3)
                {
                    
                    mapDef.MapData[i].Tree.SelectedNode.Remove();
                    mapDef.MapData[i].Tree.Nodes[0].Nodes.Insert(selnode.Index, node);
                    mapDef.MapData[i].Tree.Nodes[0].Nodes[selnode.Index].Nodes.Add(selnode);
                    mapDef.MapData[i].Tree.Nodes[0].Nodes[selnode.Index].Expand();
                }
            }
            else
            {
                mapDef.MapData[i].Tree.Nodes[0].Nodes.Add(node);
            }
            node.ItemType = MapObject.Type.Group;
            node.ObjIndex = mapDef.MapData[i].Groups.Count;
            CreateObject(node);
        }

        #region Internal Object Create/Edit/Destroy
        public static void CreateObject(TreeNodeEx sender)
        {
            int i = mapDef.GetDocumentIndex();
            switch (sender.ItemType)
            {
                case MapObject.Type.Brush:
                    {
                        break;
                    }
                case MapObject.Type.Entity:
                    {
                        // This is handled in as 'public static void AddEntity(Vector origin, string name, bool FromNew, List<KeyValuePair<string, string>> ExtKVPs)'
                        break;
                    }
                case MapObject.Type.Face:
                    {
                        break;
                    }
                case MapObject.Type.Group:
                    {
                        MapGroup group = new MapGroup();
                        group.Name = sender.Text;
						group.Origin = GetObjectOrigin();

                        mapDef.MapData[i].Groups.Add(group);
                        break;
                    }
                case MapObject.Type.TwoDeeObj:
                    {
                        TwoDeeObj tdo = new TwoDeeObj();
                        int[] arr = (int[])sender.Tag;
                        tdo.Name = sender.Text;
                        tdo.Origin = new Vector3(0, 0, 0);
                        tdo.Sides = arr[0];
                        tdo.RadiusXY = new Vector2(arr[1], arr[2]);
                        tdo.KVPs.Add("Name", tdo.Name);
                        tdo.KVPs.Add("Origin", tdo.Origin.ToString());
                        tdo.KVPs.Add("Sides", tdo.Sides.ToString());

                        mapDef.MapData[i].TwoDeeObjects.Add(tdo);

                        break;
                    }
                case MapObject.Type.Worldspawn:
                    {
                        break;
                    }
            }
            
        }
        public static void EditObject(TreeNodeEx sender)
        {
       
        }
        public static void DestroyObject(TreeNodeEx sender)
        {
			//This current method doesnt work since objIndex is not the same when you start removing stuff.
			//FIXME
            int i = mapDef.GetDocumentIndex();
            switch (sender.ItemType)
            {
                case MapObject.Type.Brush:
                    {
						break;
                    }
                case MapObject.Type.Entity:
                    {
                        
                        break;
                    }
                case MapObject.Type.Face:
                    {
						break;
                    }
                case MapObject.Type.Group:
                    {
						break;
                    }
                case MapObject.Type.TwoDeeObj:
                    {
						break;
                    }
                case MapObject.Type.Worldspawn:
                    {
                        //Cannot delete worldspawn, thus do nothing.
                        break;
                    }
            }
			functions.InvalidateViewports();
        }
        #endregion

        public static Vector3 GetObjectOrigin()
        {
            Vector3 vec3 = new Vector3();
            //method to get origin goes here
             //vec.X
             //vec.Y
             //vec.Z
            return vec3;
        }
       
        public static void DestroyMap(int MapIndex)
        {
            mapDef.MapData.RemoveAt(MapIndex);
			Globals.NumDocs--;
        }

		public static void SelectObj(MapObject.Type Type, int indexPtr)
		{
			//First, select the object through frustrum op, then select it in the treeview, finally show the properties for the object. 
			
			switch (Type)
			{
				case MapObject.Type.Brush:
					break;
				case MapObject.Type.Entity:
					break;
				case MapObject.Type.Face:
					break;
				case MapObject.Type.Group:
					break;
				case MapObject.Type.TwoDeeObj:
					break;
			}
			Program.ObjPane.tabControl2.SelectedIndex = 1; //switch to properties pane
		}

        public static String ReadXMLDocument(XmlReader reader)
        {
            // read (pull) the next node in document order
            RichTextBox rtb = new RichTextBox();
            while (reader.Read())
            {
                // get the current node's (namespace) name
                String sNodeName = (reader.NodeType == XmlNodeType.Element ||
                  reader.NodeType == XmlNodeType.EndElement) ?
                  reader.NamespaceURI + "#" + reader.Name : reader.Name;
                rtb.Text += sNodeName + Environment.NewLine;
            }
            return rtb.Text;
        }

    }
}
